﻿#region Header

/*
Remote views based on linq
By

Pascal Hauser 
Dipl. Ing. in Informatik, Hochschule für Technik Rapperswil, 2006
Master Thesis, Hochschule für Technik Rapperswil, 2008-2010

and

Raphael Gfeller
Dipl. Ing. in Informatik, Hochschule für Technik Rapperswil, 2006
Master Thesis, Hochschule für Technik Rapperswil, 2008-2010

*/

#endregion

#region Usings

using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Linq;
using Sebarf.Core.Interfaces;
using Utils;

#endregion

namespace Sebastof.Services.Interfaces {
	/// <summary>
	/// Base class for realisation an application object
	/// </summary>
	[Serializable]
	public abstract class SebastofApplicationObject : INotifyPropertyChanged, ISebastofApplicationObject, IIdentifiable,
													  IRestorableObject {
		#region EObserverNotifyState enum

		public enum EObserverNotifyState {
			NotifyObservers,
			DoNotNotifyServers
		}

		#endregion

		protected bool m_isResored;
		private int m_version;

		public EObserverNotifyState ObserverNotifyState { get; set; }

		#region Public Properties

		public IServiceLocatorService AttachedServiceLocatorService {
			get { return m_attachedContext; }
			set {
				if (m_attachedContext != null) {
					if (
						m_attachedContext.GetRegisteredService<IChangeTrackingStorageService>().CurrentDepositedObjectsHaveChanges.
							Contains(this)) {
						m_attachedContext.GetRegisteredService<IChangeTrackingStorageService>().CurrentDepositedObjectsHaveChanges.Remove
							(this);
					}
				}
				m_attachedContext = value;
			}
		}

		public virtual IDataHandlingStrategy UsedDataHandlingStrategy {
			get {
				if (m_dataHandlingStrategy == null) {
					m_dataHandlingStrategy = new StandardDataHandlingStrategy(this);
				}
				return m_dataHandlingStrategy;
			}
			set { m_dataHandlingStrategy = value; }
		}

		#endregion

		#region Public Methods

		public SebastofApplicationObject() {
			UsedDataHandlingStrategy = new StandardDataHandlingStrategy(this);
			Id = Guid.NewGuid().ToString();
		}

		public virtual T GetValue<T>(string key) {
			return UsedDataHandlingStrategy.GetValue<T>(key, this);
		}

		public virtual Object GetValue(string key) {
			return UsedDataHandlingStrategy.GetValue(key, this);
		}

		public virtual void SetValue(string key, object value) {
			bool isDifferent = UsedDataHandlingStrategy.IsDifferent(key, value, this);
			UsedDataHandlingStrategy.SetValue(key, value, this);

			if (ObserverNotifyState == EObserverNotifyState.NotifyObservers) {
				foreach (IAppliedChangesOnObjectsCollectorService observer in GetObserver()) {
					observer.DepositeValueChangedEntry(key, value, this);
				}

				if (PropertyChanged != null && isDifferent) {
					PropertyChanged(this, new PropertyChangedEventArgs(key));
				}
			}
		}

		public virtual void SignalIsCommited() {
			foreach (IAppliedChangesOnObjectsCollectorService observer in GetObserver()) {
				observer.DepositeObjectWasCommited(this);
			}
		}

		public override string ToString() {
			return "InterLinqApplicationObject." + Id;
		}

		#endregion

		#region Private Methods

		protected List<IAppliedChangesOnObjectsCollectorService> GetObserver() {
			if (m_setValueObserver == null) {
				m_setValueObserver = new List<IAppliedChangesOnObjectsCollectorService>();
			}
			return new List<IAppliedChangesOnObjectsCollectorService>(m_setValueObserver.ToArray());
		}

		protected void ThrowPropertyChanged(string property) {
			if (PropertyChanged != null) {
				PropertyChanged(this, new PropertyChangedEventArgs(property));
			}
		}

		#endregion

		#region Private Fields

		[NonSerialized]
		private IServiceLocatorService m_attachedContext;
		[NonSerialized]
		private IDataHandlingStrategy m_dataHandlingStrategy;

		[NonSerialized]
		private List<IAppliedChangesOnObjectsCollectorService> m_setValueObserver =
			new List<IAppliedChangesOnObjectsCollectorService>();

		#endregion

		#region INotifyPropertyChanged Members

		public event PropertyChangedEventHandler PropertyChanged;

		#endregion

		#region IRestorableObject Members

		public void Restored() {
			if (!m_isResored) {
				OnRestoring();
				m_isResored = true;
			}
		}

		#endregion

		#region ISebastofApplicationObject Members

		public string Id { get; set; }

		public KeyValuePair<string, object>[] GetValues() {
			return UsedDataHandlingStrategy.GetValues().First(x => x.Key == this).Value;
		}

		public void RegisterSetValueObserver(IAppliedChangesOnObjectsCollectorService callback) {
			if (m_setValueObserver == null) {
				m_setValueObserver = new List<IAppliedChangesOnObjectsCollectorService>();
			}
			m_setValueObserver.Add(callback);
		}

		public void DeRegisterSetValueObserver(IAppliedChangesOnObjectsCollectorService callback) {
			if (m_setValueObserver == null) {
				m_setValueObserver = new List<IAppliedChangesOnObjectsCollectorService>();
			}
			m_setValueObserver.Remove(callback);
		}

		public object GetVersion() {
			return m_version;
		}

		public bool CurrentVersionMatchs(object previousVersion) {
			return m_version == (int)previousVersion;
		}

		public object IncreaseVersion() {
			int ret;
			lock (this) {
				m_version++;
				ret = m_version;
			}
			return ret;
		}

		public void SetVersion(object o) {
			lock (this) {
				m_version = (int)o;
			}
		}

		#endregion

		protected virtual void OnRestoring() {
		}
	}
}